package switchviz.graphic.gauge;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import javax.media.opengl.GL;
import javax.swing.JPanel;

import org.jdom.Element;

import switchviz.graphic.GraphicFactory;
import switchviz.graphic.GraphicsPanel;
import switchviz.graphic.signal.BasicSignalDataModel;
import switchviz.graphic.signal.ComplexSignal;
import switchviz.graphic.signal.IGaugeSignal;
import switchviz.graphic.signal.ListSignalElement;
import switchviz.graphic.signal.SignalConfigurationPanel;
import switchviz.graphic.signal.SignalsConfigurationPersistence;
import switchviz.graphic.signal.TestSignal;
import switchviz.graphic.signal.UpSignal;

public abstract class IGauge 
{
	protected String _type;
	protected Element _root;
	
	protected static final String SIGNAL = "signallist";
	private SignalConfigurationPanel _sigpanel = null;
	private IGaugeSignal[] signals;
	private IGaugeSignal[] visiblesignals;
	private boolean _demo = false;
	
	public IGauge(String type, Element root)
	{
		_type = type;
		_root = root;
	}
	
	public List<JPanel> getSetupPanel()
	{
		ArrayList<JPanel> panellist = new ArrayList<JPanel>();
		
		addSetupPanels(panellist);
		
		panellist.add(getSignalPanel());
		
		JPanel previewpanel = new GraphicsPanel(new GaugePreviewEventListener(_type, _root));
		previewpanel.setName("Preview");
		panellist.add(previewpanel);
		
		return panellist;
	}
	
	public List<JPanel> getViewGaugePanel()
	{
		ArrayList<JPanel> panellist = new ArrayList<JPanel>();
		addSetupPanels(panellist);
		return panellist;
	}
	
	public Element getElement()
	{
		saveSetupPanels();
		
		Element _signode = getSignalPanel().getElement();
		_root.removeContent(_root.getChild(SIGNAL));
		_root.addContent(_signode);
		
		return _root;
	}
	
	public Element getSignalElement()
	{
		Element signalnode = null;
		if(_root.getChild(SIGNAL) == null)
		{
			signalnode = new Element(SIGNAL);
			_root.addContent(signalnode);
		}
		else
		{
			signalnode = _root.getChild(SIGNAL);
		}
		return signalnode;
	}
	
	
	public IGaugeSignal[] getSignals()
	{
		if (signals == null)
			initSignals();
		
		return signals;
	}
	
	public IGaugeSignal[] getVisibleSignals()
	{
		if (visiblesignals == null)
			initSignals();
		
		return visiblesignals;
	}
	
	public void setSignals(IGaugeSignal[] signals)
	{
		this.signals = signals;
	}
	
	public void setVisibleSignals(IGaugeSignal[] visiblesignals)
	{
		this.visiblesignals = visiblesignals;
	}
	
	public void setDemo(boolean demo) 
	{
		_demo = demo;
		initSignals();
	}

	private void initSignals()
	{
		List<IGaugeSignal> visiblelist = new LinkedList<IGaugeSignal>();
		List<IGaugeSignal> snmplist = new LinkedList<IGaugeSignal>();
		
		SignalsConfigurationPersistence scp = new SignalsConfigurationPersistence(getSignalElement());
		ListSignalElement[] siglist = scp.getAllSignalDataModel();
		
		if(siglist != null)
		{
			if (!_demo && getGaugeDataModel().isMultiplePerPort())
				snmplist.add(new UpSignal(getGaugeDataModel().getPort()));
			
			IGaugeSignal[] sig = new IGaugeSignal[siglist.length];
			
			for(int i = 0; i < siglist.length; ++i)
				sig[i] = GraphicFactory.getInstance().getSignal(siglist[i].getDatamodel().getType(), siglist[i].getElement());
			
			
			for(int i = 0; i < siglist.length; ++i)
			{	
				if (!_demo && sig[i].getType() == BasicSignalDataModel.TYPESIMPLE)
					snmplist.add(sig[i]);
				
				
				if (!_demo)
				{
					if (sig[i].getType() == BasicSignalDataModel.TYPETEST)
					{
						((TestSignal)sig[i]).setOffset(getGaugeDataModel().getDataMin());
						((TestSignal)sig[i]).setCoefficient((getGaugeDataModel().getDataMax()-getGaugeDataModel().getDataMin())/100.f);
					
					}
					
					if (sig[i].getPriority() < 2)
						visiblelist.add(sig[i]);
				}
				else
				{
					if (sig[i].getType() != BasicSignalDataModel.TYPECOMPLEX)
					{
						sig[i] = new TestSignal(sig[i].getElement());
						((TestSignal)sig[i]).setOffset(getGaugeDataModel().getDataMin());
						((TestSignal)sig[i]).setCoefficient((getGaugeDataModel().getDataMax()-getGaugeDataModel().getDataMin())/100.f);
					}
					
					if (sig[i].getPriority() < 2)
						visiblelist.add(sig[i]);
				}	
			
			}
			addToComplexSignals(sig);
		}
		signals = new IGaugeSignal[snmplist.size()];
		visiblesignals = new IGaugeSignal[visiblelist.size()];
		
		signals = snmplist.toArray(signals);
		visiblesignals = visiblelist.toArray(visiblesignals);
	}
	
	private void addToComplexSignals(IGaugeSignal[] signals)
	{
		for (int i=0; i<signals.length; i++)
		{
			if (signals[i].getType().equals(BasicSignalDataModel.TYPECOMPLEX))
			{
				for (int j=0; j<signals.length; j++)
				{
					if(i != j)
					{
						((ComplexSignal) signals[i]).addSimpleSignal(signals[j]);
					}
				}
			}
		}
	}
	
	private SignalConfigurationPanel getSignalPanel()
	{
		if (_sigpanel == null)
			_sigpanel = new SignalConfigurationPanel(getSignalElement());
		
		return _sigpanel;
	}
	
	public boolean isConnected()
	{
		if (!_demo && getGaugeDataModel().isMultiplePerPort() && signals[0].getValue() != 1.0f)
			return false;
		else
			return true;
	}
	
	public String toString()
	{
		return getGaugeDataModel().getName() + " [" + getGaugeDataModel().getType() + "]";
	}
	
	public abstract GaugeDataModel getGaugeDataModel();
	
	public abstract void addSetupPanels(List<JPanel> panellist);
	
	public abstract void saveSetupPanels();
	
	public abstract void setElement(Element node);
	
	public abstract void draw(GL gl);
	
	public abstract void initialize(GL gl);
	
	public abstract void setEnable(boolean enable);
	
	public abstract void setDetailLevel(int level);
	
	public abstract void setFreeze(boolean b);
	
	public abstract void resetData();
}
